import type { RouteRecordRaw, RouteComponent } from 'vue-router';
import { asyncForEachRecursively } from '@/utils/array-recursion'
import { constantRoutes, dynamicRoutes } from '@/router/routes'

import { buildMenuFromRoutes } from '@/utils/router-menu'

export interface ModulePathInfo {
    path: string
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    module: any
}

export interface PagePath {
    path: string
    title?: string
    permission?: string
    children?: PagePath[]
}


export type Lazy<T> = () => Promise<T>

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function setRoutesComponents(pathViewInfos: { path: string, module: any }[], routes: RouteRecordRaw[]) {
    await asyncForEachRecursively(routes, async (route, index, arr, parentRoute) => {
        if (!route.meta) {
            route.meta = {}
        }
        if (!parentRoute) {
            route.meta.url = route.path;
        } else {
            route.meta.url = (parentRoute.meta!.url + "/" + route.path).replaceAll(
                "//",
                "/"
            );
        }
        if (Array.isArray(route.children) && route.children.length > 0) {
            route.meta.type = "Directory";
        } else {
            route.meta.type = "Page";
        }

        if (typeof route.component == 'function') {
            const routeModule = await new Promise((resolve) => {
                (route.component as Lazy<RouteComponent>)().then((_component) => {
                    resolve(_component)
                })
            })

            const routeComponentPath = pathViewInfos.find((info) => {
                return info.module === routeModule
            })?.path
            
            route.meta.componentPath = routeComponentPath
        }
    })

    return routes
}



async function prepareModulePathInfos(): Promise<ModulePathInfo[]> {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const modules: Record<string, any> = import.meta.glob('@/views/**/*.vue')
    for (const key in modules) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        modules[key] = await (modules[key]() as any)
    }
    return Object.keys(modules).map((viewPath) => {
        return {
            // path: viewPath.replace('/src/views/', '').replace('.vue', ''),
            path: viewPath.replace('/src/', '').replace('.vue', ''),
            module: modules[viewPath]
        }
    });
}


export async function loadPagePathTree(): Promise<[PagePath[], Record<string, PagePath>]> {
    const modulePathInfos = await prepareModulePathInfos()

    const pathModuleMap: Record<string, PagePath> = {};

    await asyncForEachRecursively(constantRoutes.concat(dynamicRoutes), async (route) => {
        if (!Array.isArray(route.children) || route.children.length == 0) {
            let routeComponentPath: string | undefined = undefined
            if (typeof route.component == 'function') {
                const routeModule = await new Promise((resolve) => {
                    (route.component as Lazy<RouteComponent>)().then((_component) => {
                        resolve(_component)
                    })
                })

                routeComponentPath = modulePathInfos.find((info) => {
                    return info.module === routeModule
                })?.path

            }else {
                routeComponentPath = modulePathInfos.find((info) => {
                    return info.module.default === route.component
                })?.path
            }

            if(routeComponentPath) {
                const moduleInfo: PagePath = {
                    path: routeComponentPath,
                    title: route.meta?.title as string | undefined,
                    permission: route.meta?.permission as string | undefined,
                }
                pathModuleMap[routeComponentPath] = moduleInfo
            }
        }
    })

    const pathModuleTree: PagePath[] = [];
    const tempPathMap: Record<string, PagePath> = {};
    Object.keys(pathModuleMap).forEach((viewPath: string) => {
        const viewPathParts = viewPath.split("/");
        const module = pathModuleMap[viewPath]
        for (let i = 0; i < viewPathParts.length; i++) {
            const parentPath = viewPathParts.slice(0, i).join("/");
            const currentPath = viewPathParts.slice(0, i + 1).join("/");
            let pathItem = tempPathMap[currentPath];
            if (!pathItem) {
                pathItem = {
                    path: currentPath,
                    title: currentPath == viewPath ? module?.title : undefined,
                    children: [],
                };
                tempPathMap[currentPath] = pathItem;
                if (parentPath) {
                    const parentPathItem = tempPathMap[parentPath];
                    if (parentPathItem) {

                        parentPathItem.children!.push(pathItem);
                    }
                } else {
                    pathModuleTree.push(pathItem);
                }
            }
        }
    })


    return [pathModuleTree, pathModuleMap]
}





export async function scanLocalMenu() {
    const modulePathInfos = await prepareModulePathInfos()

    await asyncForEachRecursively(dynamicRoutes, async (route, index, arr, parentRoute) => {
        if (!route.meta) {
            route.meta = {}
        }
        if (!parentRoute) {
            route.meta.url = route.path;
        } else {
            route.meta.url = (parentRoute.meta!.url + "/" + route.path).replaceAll(
                "//",
                "/"
            );
        }
        if (Array.isArray(route.children) && route.children.length > 0) {
            route.meta.type = "Directory";
        } else {
            route.meta.type = "Page";
        }

        if (typeof route.component == 'function') {
            const routeModule = await new Promise((resolve) => {
                (route.component as Lazy<RouteComponent>)().then((_component) => {
                    resolve(_component)
                })
            })

            const routeComponentPath = modulePathInfos.find((info) => {
                return info.module === routeModule
            })?.path
            
            route.meta.componentPath = routeComponentPath
        }
    })

    const menu = buildMenuFromRoutes(dynamicRoutes)
    return menu
}